package cn.tedu.csmall.passport.service.impl;

import cn.tedu.csmall.passport.exception.ServiceException;
import cn.tedu.csmall.passport.mapper.AdminMapper;
import cn.tedu.csmall.passport.mapper.AdminRoleMapper;
import cn.tedu.csmall.passport.pojo.dto.AdminAddNewDTO;
import cn.tedu.csmall.passport.pojo.dto.AdminLoginDTO;
import cn.tedu.csmall.passport.pojo.entity.Admin;
import cn.tedu.csmall.passport.pojo.entity.AdminRole;
import cn.tedu.csmall.passport.pojo.vo.AdminListItemVO;
import cn.tedu.csmall.passport.pojo.vo.AdminStandardVO;
import cn.tedu.csmall.passport.security.AdminDetails;
import cn.tedu.csmall.passport.service.AdminService;
import cn.tedu.csmall.passport.web.ServiceCode;
import com.alibaba.fastjson.JSON;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * 处理管理员数据的业务实现类
 *
 * @author Chen
 * @since 2023/1/11 13:10:10
 */
@Slf4j
@Service
public class AdminServiceImpl implements AdminService {

    @Value("${csmall.jwt.secret-key}")
    private String secretKey;
    @Value("${csmall.jwt.duration-in-minute}")
    private Long durationInMinute;

    @Autowired
    private AdminMapper adminMapper;
    @Autowired
    private AdminRoleMapper adminRoleMapper;
    @Autowired
    private AuthenticationManager authenticationManager;
    @Autowired
    private PasswordEncoder passwordEncoder;

    public AdminServiceImpl() {
        log.debug("创建业务实现类对象：AdminServiceImpl");
    }

    @Override
    public String login(AdminLoginDTO adminLoginDTO) {
        log.debug("开始处理【管理员登录】的业务，参数：{}", adminLoginDTO);
        // 执行认证
        Authentication authentication = new UsernamePasswordAuthenticationToken(
                adminLoginDTO.getUsername(), adminLoginDTO.getPassword());
        // 以下调用方法时需要获取返回值
        Authentication authenticationResult = authenticationManager.authenticate(authentication);
        AdminDetails principal = (AdminDetails) authenticationResult.getPrincipal();
        log.debug("认证通过，结果：{}", authenticationResult);
        log.debug("认证通过，当事人：{}", principal);

        // 将通过认证的管理员的相关信息存入JWT中
//        String secretKey = "asdasdasdasdas";
        Date date = new Date(System.currentTimeMillis() + durationInMinute * 60 * 1000L);
        Map<String, Object> claims = new HashMap<>();
        claims.put("id", principal.getId());
        claims.put("username", principal.getUsername());
        Collection<GrantedAuthority> authorities = principal.getAuthorities();
        String authoritiesJsonString = JSON.toJSONString(authorities);
        log.debug("权限列表，字符串值：{}", authorities);
        log.debug("权限列表，JSON结果：{}", authoritiesJsonString);
        claims.put("authoritiesJsonString", authoritiesJsonString);
        // 生成JWT
        String jwt = Jwts.builder()
                .setHeaderParam("alg", "HS256")
                .setHeaderParam("typ", "JWT")
                .setClaims(claims)
                .setExpiration(date)
                .signWith(SignatureAlgorithm.HS256, secretKey)
                .compact();
        return jwt;
    }

    @Override
    public void addNew(AdminAddNewDTO adminAddNewDTO) {
        log.debug("开始处理【添加管理员】的业务，参数：{}", adminAddNewDTO);
        Long[] roleIds = adminAddNewDTO.getRoleIds();

        // 不允许新的管理员分配1号角色
        for (Long roleId : roleIds) {
            if (roleId == 1) {
                String message = "添加管理员失败，非法访问（不允许为管理员分配1号角色）！";
                log.warn(message);
                throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
            }
        }

        // 从参数对象中取出用户名
        String username = adminAddNewDTO.getUsername();
        int countByUsername = adminMapper.countByUsername(username);
        // 判断统计结果是否大于0
        if (countByUsername > 0) {
            // 是：抛出异常（ERR_CONFLICT）
            String message = "添加管理员失败，尝试使用的用户名已经被占用！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
        }

        // 从参数对象中取出手机号码
        String phone = adminAddNewDTO.getPhone();
        // 调用adminMapper.countByPhone()执行统计
        int countByPhone = adminMapper.countByPhone(phone);
        // 判断统计结果是否大于0
        if (countByPhone > 0) {
            // 是：抛出异常（ERR_CONFLICT）
            String message = "添加管理员失败，尝试使用的手机号码已经被占用！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
        }

        // 从参数对象中取出电子邮箱
        String email = adminAddNewDTO.getEmail();
        // 调用adminMapper.countByEmail()执行统计
        int countByEmail = adminMapper.countByEmail(email);
        // 判断统计结果是否大于0
        if (countByEmail > 0) {
            // 是：抛出异常（ERR_CONFLICT）
            String message = "添加管理员失败，尝试使用的电子邮箱已经被占用！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
        }

        // 创建Admin对象
        log.debug("即将插入数据，参数：{}", adminAddNewDTO);
        Admin admin = new Admin();
        BeanUtils.copyProperties(adminAddNewDTO, admin);
        // 将密码加密
        String rawPassword = admin.getPassword();
        String encodePassword = passwordEncoder.encode(rawPassword);
        admin.setPassword(encodePassword);
        // 初始登录次数
        admin.setLoginCount(0);

        {
            // 调用adminMapper.insert()方法插入管理员数据
            int rows = adminMapper.insert(admin);
            if (rows != 1) {
                String message = "添加管理员失败，服务器忙，请稍后再尝试！";
                log.warn(message);
                throw new ServiceException(ServiceCode.ERR_INSERT, message);
            }
        }

        {
            AdminRole[] adminRoles = new AdminRole[roleIds.length];
            for (int i = 0; i < adminRoles.length; i++) {
                AdminRole adminRole = new AdminRole();
                adminRole.setAdminId(admin.getId());
                adminRole.setRoleId(roleIds[i]);
                adminRoles[i] = adminRole;
            }

            int rows = adminRoleMapper.insertBatch(adminRoles);
            if (rows < 1) {
                String message = "添加管理员失败，服务器忙，请稍后再尝试！";
                log.warn(message);
                throw new ServiceException(ServiceCode.ERR_INSERT, message);
            }
        }

    }

    @Override
    public void delete(Long id) {
        log.debug("开始处理【根据id删除删除管理员】的业务，参数：{}", id);
        // 是否是1号管理员
        if (id == 1) {
            String message = "不允许删除1号管理员！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_DELETE, message);
        }

        // 检查数据是否存在
        AdminStandardVO adminStandardVO = adminMapper.getStandardById(id);
        if (adminStandardVO == null) {
            String message = "删除管理员失败，尝试删除的管理员不存在！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);
        }

        // 执行删除
        log.debug("即将执行删除关联数据，参数：{}", id);
        int rows = adminMapper.deleteById(id);
        if (rows != 1) {
            String message = "删除管理员失败，服务器忙，请稍后再尝试！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_DELETE, message);
        }

        // 删除关联到的数据
        rows = adminRoleMapper.deleteByAdminId(id);
        if (rows < 1) {
            String message = "删除管理员失败，服务器忙，请稍后再尝试！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_DELETE, message);
        }
    }

    @Override
    public void setEnable(Long id) {
        updateEnableById(id, 1);
    }

    @Override
    public void setDisable(Long id) {
        updateEnableById(id, 0);
    }

    private void updateEnableById(Long id, Integer enable) {
        String[] enableText = {"禁用", "启用"};
        log.debug("开始处理【{}管理员】的业务，ID：{}，目标状态：{}", enableText[enable], id, enableText);
        // 不允许禁用1号管理员
        if (id == 1) {
            String message = enableText[enable] + "类别失败，不允许" + enableText[enable] + "系统管理员！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
        }
        // 调用Mapper对象的getStandardById()方法执行查询
        AdminStandardVO adminStandardVO = adminMapper.getStandardById(id);
        if (adminStandardVO == null) {
            String message = enableText[enable] + "类别失败，尝试处理的管理员不存在！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);
        }
        // 判断以上查询结果中的enable是否与参数enable相同
        if (adminStandardVO.getEnable().equals(enable)) {
            // 是：抛出异常（CONFLICT）
            String message = enableText[enable] + "类别失败，尝试处理的管理员已处于" + enableText[enable] + "状态！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
        }
        // 准备执行更新
        Admin admin = new Admin();
        admin.setId(id);
        admin.setEnable(enable);
        // 调用Mapper对象的update()执行更新，并获取返回结果，判断是否符合预期值
        log.debug("即将修改数据，参数：{}", admin);
        int rows = adminMapper.update(admin);
        if (rows != 1) {
            String message = enableText[enable] + "类别失败，服务器忙，请稍后再次尝试！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_UPDATE, message);
        }
    }

    @Override
    public List<AdminListItemVO> list() {
        log.debug("开始处理【查询管理员列表】的业务，参数：无");
        List<AdminListItemVO> list = adminMapper.list();

        Iterator<AdminListItemVO> iterator = list.iterator();
        while (iterator.hasNext()) {
            AdminListItemVO admin = iterator.next();
            if (admin.getId() == 1) {
                iterator.remove();
                break;
            }
        }
        return list;
    }

}
